package com.hospital.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.constant.MessageConstant;
import com.hospital.dto.PatientPageQueryDTO;
import com.hospital.dto.PatientRegisterDTO;
import com.hospital.entity.*;
import com.hospital.enumeration.BedStatus;
import com.hospital.enumeration.BusinessExceptionEnum;
import com.hospital.enumeration.Gender;
import com.hospital.exception.BusinessException;
import com.hospital.mapper.*;
import com.hospital.result.PageResult;
import com.hospital.service.*;
import com.hospital.service.util.PatientCheckUtil;
import com.hospital.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class PatientServiceImpl extends ServiceImpl<PatientMapper, Patient> implements PatientService {
    @Autowired
    private PatientMapper patientMapper;
    @Autowired
    private HospitalizationRecordMapper hospitalizationRecordMapper;
    @Autowired
    private BillMapper billMapper;
    @Autowired
    private TreatmentRecordMapper treatmentRecordMapper;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private WardMapper wardMapper;
    @Autowired
    private TreatmentMapper treatmentMapper;

    @Autowired
    private BedService bedService;
    @Autowired
    private DoctorService doctorService;
    @Autowired
    private TreatmentService treatmentService;

    @Autowired
    private PatientCheckUtil patientCheckUtil;

    /**
     * 病人入院
     *
     * @param patientRegisterDTO 病人注册信息
     */
    @Transactional
    @Override
    public void addPatient(PatientRegisterDTO patientRegisterDTO) {
        // patient表（添加）
        Patient patient = Patient.builder()
                .name(patientRegisterDTO.getName())
                .gender(Gender.fromValue(patientRegisterDTO.getGender()))
                .address(patientRegisterDTO.getAddress())
                .phoneNumber(patientRegisterDTO.getPhoneNumber())
                .build();
        patientMapper.insert(patient);
        // bed表（状态更改）- 随机分配对应科室的空床位
        Long bedId = bedService.assignBed(patientRegisterDTO.getDeptId());

        // doctor表（分配，状态更改） - 随机分配对应科室的医生
        Long doctorId = doctorService.assignDoctor(patientRegisterDTO.getDeptId());

        // hospitalizationrecord表（添加）
        // 找ward_id
        Bed bed = bedService.getById(bedId);
        Long wardId = bed.getWardId();
        HospitalizationRecord hospitalizationRecord = HospitalizationRecord.builder()
                .patientId(patient.getPatientId())
                .wardId(wardId)
                .bedId(bedId)
                .admissionTime(patientRegisterDTO.getAdmissionTime())
                .build();
        hospitalizationRecordMapper.insert(hospitalizationRecord);

        // treatmentrecord表（添加） - 随机分配对应科室的诊疗方案
        Long treatmentId = treatmentService.assignTreatment(patientRegisterDTO.getDeptId());
        TreatmentRecord treatmentRecord = TreatmentRecord.builder()
                .patientId(patient.getPatientId())
                .doctorId(doctorId)
                .treatmentTime(patientRegisterDTO.getAdmissionTime())
                .diagnosis(patientRegisterDTO.getDiagnosis())
                .treatmentId(treatmentId)
                .build();
        treatmentRecordMapper.insert(treatmentRecord);


        // bill表（添加）
        Bill bill = Bill.builder()
                .patientId(patient.getPatientId())
                .wardId(wardId)
                .build();
        billMapper.insert(bill);
    }

    /**
     * 病人出院信息
     *
     * @param patientId
     * @return
     */
    @Override
    public DischargeInfoVO getDischargeInfo(Long patientId) {
        DischargeInfoVO dischargeInfoVO = new DischargeInfoVO();
        // 病人表
        Patient patient = patientMapper.selectById(patientId);

        // 检查操作是否合法
        patientCheckUtil.checkPatient(patient);

        BeanUtils.copyProperties(patient, dischargeInfoVO);

        // 住院记录表
        HospitalizationRecord hospitalizationRecord = hospitalizationRecordMapper.selectById(patientId);
        BeanUtils.copyProperties(hospitalizationRecord, dischargeInfoVO);

        // 科室表
        Ward ward = wardMapper.selectOne(
                new LambdaQueryWrapper<Ward>()
                        .eq(Ward::getWardId, hospitalizationRecord.getWardId())
        );
        Department department = departmentMapper.selectById(ward.getDeptId());
        dischargeInfoVO.setDeptName(department.getDeptName());

        // 治疗记录表和诊疗方案表
        dischargeInfoVO.setDischargeTime(LocalDateTime.now());
        Long treatmentId = treatmentRecordMapper.selectOne(
                new LambdaQueryWrapper<TreatmentRecord>()
                        .eq(TreatmentRecord::getPatientId, patientId)
        ).getTreatmentId();
        BigDecimal treatmentCost = treatmentMapper.selectById(treatmentId).getTreatmentCost();
        dischargeInfoVO.setTreatmentCost(treatmentCost);

        // 病房表
        // 计算病人住院天数
        Duration duration = Duration.between(dischargeInfoVO.getAdmissionTime(), dischargeInfoVO.getDischargeTime());
        long days = duration.toDays();

        // 计算床位费用
        BigDecimal bedCost = ward.getChargeStandard().multiply(BigDecimal.valueOf(days));
        dischargeInfoVO.setBedCost(bedCost);

        return dischargeInfoVO;
    }

    /**
     * 病人出院
     *
     * @param patientId
     */
    @Override
    public void discharge(Long patientId) {
        Patient patient = patientMapper.selectById(patientId);

        // 检查操作是否合法
        patientCheckUtil.checkPatient(patient);

        // bed表（状态更改）
        HospitalizationRecord hospitalizationRecord = hospitalizationRecordMapper.selectById(patientId);
        Bed bed = bedService.getById(hospitalizationRecord.getBedId());
        bed.setStatus(BedStatus.AVAILABLE);
        bedService.updateById(bed);

        // doctor表（状态更改）
        TreatmentRecord treatmentRecord = treatmentRecordMapper.selectById(patientId);
        Doctor doctor = doctorService.getById(treatmentRecord.getDoctorId());
        doctor.setCurrentPatientCount(doctor.getCurrentPatientCount() - 1);
        doctorService.updateById(doctor);

        // hospitalization_record表（状态更改）
        LocalDateTime dischargeTime = LocalDateTime.now();
        hospitalizationRecord.setDischargeTime(dischargeTime);
        hospitalizationRecordMapper.updateById(hospitalizationRecord);

        // bill表（更改）
        Bill bill = billMapper.selectById(patientId);
        bill.setSettlementTime(dischargeTime);

        // 治疗记录表和诊疗方案表
        Long treatmentId = treatmentRecordMapper.selectOne(
                new LambdaQueryWrapper<TreatmentRecord>()
                        .eq(TreatmentRecord::getPatientId, patientId)
        ).getTreatmentId();
        BigDecimal treatmentCost = treatmentMapper.selectById(treatmentId).getTreatmentCost();
        bill.setTreatmentFee(treatmentCost);

        // 计算病人住院天数
        Duration duration = Duration.between(hospitalizationRecord.getAdmissionTime(), hospitalizationRecord.getDischargeTime());
        long days = duration.toDays();

        // 计算床位费用
        Ward ward = wardMapper.selectById(hospitalizationRecord.getWardId());
        BigDecimal bedCost = ward.getChargeStandard().multiply(BigDecimal.valueOf(days));
        bill.setHospitalizationFee(bedCost);

        billMapper.updateById(bill);
    }

    @Override
    public PageResult getPatientListPage(PatientPageQueryDTO patientPageQueryDTO) {
        IPage<PatientListVO> page = new Page<>(patientPageQueryDTO.getPageNumber(), patientPageQueryDTO.getPageSize());

        patientMapper.pageQuery(page, patientPageQueryDTO);

        return PageResult.builder()
                .total(page.getTotal())
                .records(page.getRecords())
                .build();
    }

    @Override
    public PatientInfoVO getPatientInfo(Long patientId) {
        PatientInfoVO patientInfoVO = new PatientInfoVO();

        Patient patient = patientMapper.selectById(patientId);

        // 检查操作是否合法
        patientCheckUtil.checkPatient(patient);

        BeanUtils.copyProperties(patient, patientInfoVO);
        patientInfoVO.setPatientName(patient.getName());

        // 治疗记录表
        TreatmentRecord treatmentRecord = treatmentRecordMapper.selectById(patientId);
        Doctor doctor = doctorService.getById(treatmentRecord.getDoctorId());
        Department department = departmentMapper.selectById(doctor.getDeptId());
        patientInfoVO.setDoctorName(doctor.getName());
        patientInfoVO.setDeptName(department.getDeptName());

        // 住院记录表
        HospitalizationRecord hospitalizationRecord = hospitalizationRecordMapper.selectById(patientId);
        Ward ward = wardMapper.selectById(hospitalizationRecord.getWardId());
        Bed bed = bedService.getById(hospitalizationRecord.getBedId());
        patientInfoVO.setAdmissionTime(hospitalizationRecord.getAdmissionTime());
        patientInfoVO.setWardId(ward.getWardId());
        patientInfoVO.setLocation(ward.getLocation());
        patientInfoVO.setBedId(bed.getBedId());

        return patientInfoVO;
    }

    @Override
    public PatientStatsVO getPatientStats() {
        PatientStatsVO patientStatsVO = new PatientStatsVO();

        // 获取当前时间的零点和第二天的零点
        LocalDateTime todayMidnight = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime tomorrowMidnight = todayMidnight.plusDays(1);

        // 获取总病人数
        patientStatsVO.setTotalPatientsInHospital(Math.toIntExact(hospitalizationRecordMapper.selectCount(
                new LambdaQueryWrapper<HospitalizationRecord>()
                        .isNull(HospitalizationRecord::getDischargeTime)// 入院未出院
        )));

        // 获取今日入院病人数
        patientStatsVO.setAdmissionTodayCount(Math.toIntExact(hospitalizationRecordMapper.selectCount(
                new LambdaQueryWrapper<HospitalizationRecord>()
                        .isNull(HospitalizationRecord::getDischargeTime) // 入院未出院
                        .ge(HospitalizationRecord::getAdmissionTime, todayMidnight) // 入院时间 >= 今天零点
                        .lt(HospitalizationRecord::getAdmissionTime, tomorrowMidnight) // 入院时间 < 明天零点
        )));

        // 获取今日出院病人数
        patientStatsVO.setDischargeTodayCount(Math.toIntExact(hospitalizationRecordMapper.selectCount(
                new LambdaQueryWrapper<HospitalizationRecord>()
                        .isNotNull(HospitalizationRecord::getDischargeTime) // 出院时间不为 null
                        .ge(HospitalizationRecord::getDischargeTime, todayMidnight) // 出院时间 >= 今天零点
                        .lt(HospitalizationRecord::getDischargeTime, tomorrowMidnight) // 出院时间 < 明天零点
        )));

        return patientStatsVO;
    }

    @Override
    public List<PatientGenderVO> getPatientGender() {
        List<PatientGenderVO> patientGenderVOList = new ArrayList<>();

        PatientGenderVO patientGenderVO = PatientGenderVO.builder()
                .gender(Gender.FEMALE)
                .count(Math.toIntExact(patientMapper.selectCount(
                        new LambdaQueryWrapper<Patient>()
                                .eq(Patient::getGender, Gender.FEMALE))))
                .build();

        patientGenderVOList.add(patientGenderVO);

        patientGenderVO = PatientGenderVO.builder()
                .gender(Gender.MALE)
                .count(Math.toIntExact(patientMapper.selectCount(
                        new LambdaQueryWrapper<Patient>()
                                .eq(Patient::getGender, Gender.MALE))))
                .build();

        patientGenderVOList.add(patientGenderVO);

        return patientGenderVOList;
    }
}
